// bank.cpp -- using the Queue interface
// compile with Queue.cpp

#include <iostream>
#include <cstdlib>  // for rand() and strand()
#include <ctime>    // for time()
#include "Queue.h"

const int MIN_PER_HR = 60;

bool newCustomer(double x);     // is there a new customer

int main() {
    using std::cin;
    using std::cout;
    using std::endl;
    using std::ios_base;
    // settings things up
    std::srand(std::time(nullptr)); // random initializing of rand()

    cout << "Case Study: Bank of Heather Automatic Teller\n";
    cout << "Enter maximum size of queue: ";
    int qs;
    cin >> qs;
    Queue line(qs); // line queue holds up to qs people

    cout << "Enter the number of simulation hours: ";
    int hours;  // hours of simulation
    cin >> hours;
    // simulation will run 1 cycle per minute
    long cycle_limit = MIN_PER_HR * hours;   // # of cycle

    cout << "Enter the average number of customers per hours: ";
    double per_hour; // average # of arrival per hour
    cin >> per_hour;
    double min_per_cust;    // average time between arrivals
    min_per_cust = MIN_PER_HR / per_hour;

    Item temp;          // new customers data
    long turnaways = 0;  // turned away by full queue
    long customers = 0;  // joined the queue
    long served = 0;    // server during the simulation
    long sum_line = 0;  // cumulative line length
    int wait_time = 0;  // time until auto-teller is free
    long line_wait = 0; // cumulative time in line

    // running the simulation
    for (int cycle = 0; cycle < cycle_limit; ++cycle) {
        // have newcomer
        if (newCustomer(min_per_cust)) {
            if (line.isFull())
                ++turnaways;
            else {
                ++customers;
                temp.set(cycle);    // cycle = time of arrival
                line.enqueue(temp); // add newcomer to line
            }
        }
        if (wait_time <= 0 && !line.isEmpty()) {
            line.dequeue(temp);     // attend next customers
            wait_time = temp.ptime();  // for wait_time minutes
            line_wait += cycle - temp.when();
            ++served;
        }
        if (wait_time > 0)
            --wait_time;
        sum_line += line.queueCount();
    }

    // reporting results
    if (customers > 0) {
        cout << "customers accepted: " << customers << endl;
        cout << " customers served: " << served << endl;
        cout << " turnaways: " << turnaways << endl;
        cout << "average queue size: ";
        cout.precision(2);
        cout.setf(ios_base::fixed, ios_base::floatfield);
        cout << (double) sum_line / cycle_limit << endl;
        cout << " average wait time: "
             << (double) line_wait / served << " minutes\n";
    } else
        cout << "No customers!\n";
    cout << "Done!\n";
    return 0;
}

// x = average time, in minutes, between customers
// return value is true if customer shows up this minute
bool newCustomer(double x) {
    return (std::rand() * x / RAND_MAX < 1);
}